namespace Resonator.Tests.Services
{
	using System;
	using System.Collections.Generic;
	using System.Globalization;
	using System.IO;
	using System.Text;
	using NUnit.Framework;
	using Core.Services;
	using Domain.Models;
	using Domain.Services;

	[TestFixture]
	[Category("Parser")]
	public class ResxResourceParserTester
	{
		protected static readonly string RESX_TEMPLATE =
			"<root><resheader name=\"resmimetype\"><value>text/microsoft-resx</value></resheader><resheader name=\"version\"><value>2.0</value></resheader><resheader name=\"reader\"><value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><resheader name=\"writer\"><value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader>{0}</root>";

		private IResourceParser _resourceParser;

		[SetUp]
		public void SetUp()
		{
			_resourceParser = new ResxResourceParser();
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Resouce_Stream_Is_Required()
		{
			new ResxResourceParser().Parse(null);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Default_Culture_Is_Required()
		{
			new ResxResourceParser().Parse(new ResourceStream(string.Empty, new MemoryStream()), null);
		}

		[Test]
		[ExpectedException(typeof(ResonatorException))]
		public void Valid_Resx_Required()
		{
			new ResxResourceParser().Parse(new ResourceStream(string.Empty, new MemoryStream()));
		}

		[Test]
		public void Parses_Comment_As_Context()
		{
			string resx =
				MockResx( "<data name=\"label1.Text\"><value>LabelText</value><comment>Used as context</comment></data>" );

			IList<Resource> resources;
			using( Stream stream = StringStream( resx ) )
			{
				resources = _resourceParser.Parse( new ResourceStream("Mock.resx", stream) );
			}

			Assert.IsNotNull( resources );
			Assert.AreEqual( 1, resources.Count );
			Assert.AreEqual( "Used as context", resources[0].Context );
		}

		[Test]
		public void Node_Name_Required_To_Parse_Resource()
		{
			string resx =
				MockResx("<data name=\"\"><value>LabelText</value><comment>Used as context</comment></data>");

			IList<Resource> resources;
			using (Stream stream = StringStream(resx))
			{
				resources = _resourceParser.Parse(new ResourceStream("Mock.resx", stream));
			}

			Assert.IsNotNull(resources);
			Assert.AreEqual(0, resources.Count);
		}

		[Test]
		public void Use_Default_Culture_When_Unable_To_Extract_From_Resource_Name()
		{
			string resx =
				MockResx("<data name=\"label1.Text\"><value>LabelText</value><comment>Used as context</comment></data>");
			CultureInfo defaultCulture = new CultureInfo( "es-ES" ); 

			IList<Resource> resources;
			using (Stream stream = StringStream(resx))
			{
				resources = _resourceParser.Parse(new ResourceStream("Mock.invalid.resx", stream), defaultCulture);
			}

			Assert.IsNotNull(resources);
			Assert.AreEqual(1, resources.Count);
			Assert.AreEqual( defaultCulture, resources[0].Culture ); 
		}

		[Test]
		public void Parses_Entries_With_Name_Ending_In_DotText()
		{
			string resx = MockResx( "<data name=\"label1.Text\"><value>LabelText</value></data>" );

			IList<Resource> resources;
			using( Stream stream = StringStream( resx ) )
			{
				resources = _resourceParser.Parse(new ResourceStream("Mock.resx", stream));
			}

			Assert.IsNotNull( resources );
			Assert.AreEqual( 1, resources.Count );
			Assert.AreEqual( "Mock.label1.Text", resources[0].Name );
			Assert.AreEqual( "LabelText", resources[0].Phrase );
		}

		[Test]
		public void Parses_Entries_With_Name_Ending_In_DotHeaderText()
		{
			string resx = MockResx( "<data name=\"Column1.HeaderText\"><value>HeaderText</value></data>" );

			IList<Resource> resources;
			using( Stream stream = StringStream( resx ) )
			{
				resources = _resourceParser.Parse(new ResourceStream("Mock.resx", stream));
			}

			Assert.IsNotNull( resources );
			Assert.AreEqual( 1, resources.Count );
			Assert.AreEqual( "Mock.Column1.HeaderText", resources[0].Name );
			Assert.AreEqual( "HeaderText", resources[0].Phrase );
		}

		[Test]
		public void Parses_Entries_With_Name_Ending_In_DotNullText()
		{
			string resx = MockResx( "<data name=\"Column1.NullText\"><value>(null)</value></data>" );

			IList<Resource> resources;
			using( Stream stream = StringStream( resx ) )
			{
				resources = _resourceParser.Parse(new ResourceStream("Mock.resx", stream));
			}

			Assert.IsNotNull( resources );
			Assert.AreEqual( 1, resources.Count );
			Assert.AreEqual( "Mock.Column1.NullText", resources[0].Name );
			Assert.AreEqual( "(null)", resources[0].Phrase );
		}

		[Test]
		public void Parses_Entries_With_No_Specified_Type_And_No_Periods_In_Name()
		{
			string resx = MockResx( "<data name=\"Yes\"><value>Yes</value></data>" );

			IList<Resource> resources;
			using( Stream stream = StringStream( resx ) )
			{
				resources = _resourceParser.Parse(new ResourceStream("Mock.resx", stream));
			}

			Assert.IsNotNull( resources );
			Assert.AreEqual( 1, resources.Count );
			Assert.AreEqual( "Mock.Yes", resources[0].Name );
			Assert.AreEqual( "Yes", resources[0].Phrase );
		}

		[Test]
		public void Extracts_Culture_Based_On_Standard_Resx_Naming_Conventions()
		{
			string resx = MockResx("<data name=\"Yes\"><value>Yes</value></data>");

			IList<Resource> resources;
			using (Stream stream = StringStream(resx))
			{
				ResourceStream resourceStream = new ResourceStream("Test.es-ES.resx", stream);
				resources = _resourceParser.Parse(resourceStream);
			}

			Assert.IsNotNull(resources);
			Assert.AreEqual(1, resources.Count);
			Assert.AreEqual(new CultureInfo("es-ES"), resources[0].Culture);
		}

		protected static Stream StringStream(string text)
		{
			byte[] textBytes = Encoding.UTF8.GetBytes( text );
			return new MemoryStream( textBytes );
		}

		protected static string MockResx(string data)
		{
			return string.Format( RESX_TEMPLATE, data );
		}
	}
}